package com.jfok.server.service;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.hibernate.Hibernate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.multipart.MultipartFile;

import com.artofsolving.jodconverter.DefaultDocumentFormatRegistry;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.DocumentFormat;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import com.jfok.server.DAO.SystemBaseDAO;
import com.jfok.server.common.FileUploadBean;
import com.jfok.server.hibernate.addition._Addition;
import com.jfok.server.hibernate.addition._AdditionReduceMode;
import com.jfok.server.hibernate.addition._Addition_FileData;
import com.jfok.server.hibernate.addition._Addition_ImagePreview;
import com.jfok.server.login.SessionManage;
import com.jfok.server.login.UserSession;
import com.jfok.shared.FileTypeVSMimeType;



@Service
public class AttachmentService {

	@Resource
	private SystemBaseDAO systemBaseDAO;

	@Transactional(propagation = Propagation.REQUIRED)
	public _Addition uploadnew(FileUploadBean uploaditem, BindingResult bindingResult,
			HttpServletRequest request) throws IOException {
		Map<String, Object> result = new HashMap<String, Object>();

		if (bindingResult.hasErrors()) {
			for (ObjectError error : bindingResult.getAllErrors()) {
				// 有二个错误信息，是上传日期和录入日期，传进来的是字符串，不能自动转成 Date
				// System.err.println("Error: " + error.getCode() + " - " +
				// error.getDefaultMessage());
				result.put(error.getCode(), error.getDefaultMessage());
			}
		}
		// 下划线开头的字段不能自动注入，日期也注入不对，以后再处理了，现在这里可以正确执行了
		uploaditem.set_t9502___tf_additionTypeId(request.getParameter("_t9502___tf_additionTypeId"));
		uploaditem.set_t9503___tf_additionFileTypeId(request
				.getParameter("_t9503___tf_additionFileTypeId"));
		uploaditem.set_t9506___tf_fieldId(request.getParameter("_t9506___tf_fieldId"));

		uploaditem.set_t9504___tf_reduceModeId(request.getParameter("_t9504___tf_reduceModeId"));
		UserSession userSession = SessionManage.getInstance().getUserSession(request.getSession());
		_Addition addition = new _Addition();
		MultipartFile file = uploaditem.getFile();
		if (file != null && file.getOriginalFilename().length() > 0) {
			addition.setTf_AdditionFileType(uploaditem.getTf_AdditionFileType());
			addition.setTf_AdditionReduceMode(uploaditem.getTf_AdditionReduceMode());
		}
		addition.setTf_AdditionType(uploaditem.getTf_AdditionType());
		addition.setTf_AdditionOnField(uploaditem.getTf_AdditionOnField());
		addition.setTf_moduleId(uploaditem.getTf_moduleId());
		addition.setTf_moduleIdvalue(uploaditem.getTf_moduleIdvalue());
		addition.setTf_name(uploaditem.getTf_name());
		addition.setTf_order(uploaditem.getTf_order());
		addition.setTf_remark(uploaditem.getTf_remark());
		addition.setTf_inputmen(userSession.getUserName());
		addition.setTf_inputdate(new Date());
		systemBaseDAO.save(addition);
		return addition;
	}

	@SuppressWarnings("deprecation")
	@Transactional(propagation = Propagation.REQUIRED)
	public Object uploadnewFile(MultipartFile file, Integer id) throws IOException {

		_Addition addition = (_Addition) systemBaseDAO.findById(_Addition.class, id);
		addition.setTf_filename(file.getOriginalFilename());
		addition.setTf_filesize((int) file.getSize());
		addition.setTf_filelastupdate(new Date());
		addition.setTf_imgheight(null);
		addition.setTf_imgwidth(null);

		_Addition_FileData addition_FileData = (_Addition_FileData) systemBaseDAO.findById(
				_Addition_FileData.class, addition.getTf_additionId());
		_Addition_ImagePreview addition_ImagePreview = (_Addition_ImagePreview) systemBaseDAO.findById(
				_Addition_ImagePreview.class, addition.getTf_additionId());

		// 取得压缩后的缩略图的stream
		ByteArrayOutputStream compressOK = null;
		Image image = null;
		if (FileTypeVSMimeType.isImageFile(addition.getTf_filename())) {
			image = ImageIO.read(file.getInputStream());
			compressOK = CompressImage(file.getInputStream(), addition, image);
		}
		// 如果是图形文件，写入缩略图
		if (compressOK != null) {
			addition_ImagePreview.setTf_imagePreview(Hibernate.createBlob(new ByteArrayInputStream(
					compressOK.toByteArray())));
			// 根据图形文件的压缩设置，保存原始图形
			if (saveImageWithReduceMode(addition, addition_FileData, file, image))
				;
			else
				// 如果没有压缩成功，还是保存原图
				addition_FileData.setTf_filedata(Hibernate.createBlob(file.getInputStream()));
		} else {
			addition_ImagePreview.setTf_imagePreview(null);
			addition.setTf_AdditionReduceMode(null);
			addition_FileData.setTf_filedata(Hibernate.createBlob(file.getInputStream()));
		}

		// 如果是doc ,docx 文件，那么生成一个 pdf 的放在tf_pdfdata ,预览的时候调用pdf
		String fileext = null;
		String fn = addition.getTf_filename().toLowerCase();
		if (fn.endsWith(".doc"))
			fileext = "doc";
		if (fn.endsWith(".docx"))
			fileext = "docx";
		if (fn.endsWith(".xls"))
			fileext = "xls";
		if (fn.endsWith(".xlsx"))
			fileext = "xlsx";
		if (fn.endsWith(".ppt"))
			fileext = "ppt";
		if (fn.endsWith(".pptx"))
			fileext = "pptx";

		ByteArrayOutputStream pdfos = new ByteArrayOutputStream();
		addition_FileData.setTf_pdfdata(null);
		if (fileext != null) {
			try {
				OpenOfficeConnection connection = new SocketOpenOfficeConnection(SystemGlobalInfoService
						.getSysteminfo().getTf_openOfficeURL(), 8100);
				connection.connect();

				DefaultDocumentFormatRegistry formatReg = new DefaultDocumentFormatRegistry();
				DocumentFormat pdfFormat = formatReg.getFormatByFileExtension("pdf");

				DocumentFormat docFormat = formatReg.getFormatByFileExtension(fileext);

				DocumentConverter converter = new OpenOfficeDocumentConverter(connection);

				converter.convert(file.getInputStream(), docFormat, pdfos, pdfFormat);
				connection.disconnect();
				addition_FileData.setTf_pdfdata(Hibernate.createBlob(new ByteArrayInputStream(
						((ByteArrayOutputStream) pdfos).toByteArray())));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		systemBaseDAO.attachDirty(addition_FileData, null);

		systemBaseDAO.attachDirty(addition, null);
		systemBaseDAO.attachDirty(addition_ImagePreview, null);

		return "{success:true}";
	}

	private boolean saveImageWithReduceMode(_Addition addition, _Addition_FileData fileData,
			MultipartFile file, Image image) throws IOException {
		_AdditionReduceMode mode = addition.getTf_AdditionReduceMode();
		if (mode != null) {
			if (mode.getTf_maxValue() != null && mode.getTf_maxValue() > 1) {
				// 对图像的宽高比，按照最大的进行
				return CompressImageWithMaxValue(addition, fileData, mode.getTf_maxValue(), image);
			} else if (mode.getTf_recudeTo() != null && mode.getTf_recudeTo() > 1) {
				return CompressImageWithReduce(addition, fileData, mode.getTf_recudeTo(), image);
			}
		}
		return false;
	}

	private boolean CompressImageWithMaxValue(_Addition addition, _Addition_FileData fileData,
			Integer maxValue, Image image) {
		try {

			int width = image.getWidth(null);
			int height = image.getHeight(null);
			if (width > maxValue || height > maxValue) {
				if (width > height) {
					height = new Double(1.00 * height * maxValue / width).intValue();
					width = maxValue;
				} else {
					width = new Double(1.00 * width * maxValue / height).intValue();
					height = maxValue;
				}
				saveToDbf(image, addition, fileData, width, height);
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	private boolean CompressImageWithReduce(_Addition addition, _Addition_FileData fileData,
			Integer recudeTo, Image image) {
		try {
			int width = image.getWidth(null);
			int height = image.getHeight(null);
			if (width < 800 && height < 800) // 二个都小于800，不要压缩了
				return false;
			double r = Math.sqrt(recudeTo);
			width = new Double(1.00 * width / r).intValue();
			height = new Double(1.00 * height / r).intValue();
			saveToDbf(image, addition, fileData, width, height);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	@SuppressWarnings("deprecation")
	public void saveToDbf(Image image, _Addition addition, _Addition_FileData fileData, int width,
			int height) throws IOException {
		Image simage = image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
		BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics g2d = bufferedImage.getGraphics();
		g2d.drawImage(simage, 0, 0, null);
		g2d.dispose();
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ImageIO.write(bufferedImage, "JPEG", os);
		fileData.setTf_filedata(Hibernate.createBlob(new ByteArrayInputStream(os.toByteArray())));
		addition.setTf_imgwidth(width);
		addition.setTf_imgheight(height);
		addition.setTf_filesize(os.size());
	}

	private int MAXXY = 128;

	public ByteArrayOutputStream CompressImage(InputStream is, _Addition addition, Image image) {
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		try {
			int width = image.getWidth(null);
			int height = image.getHeight(null);
			addition.setTf_imgwidth(width);
			addition.setTf_imgheight(height);
			int c_w = MAXXY;
			int c_h = MAXXY * height / width;
			if (height > width) {
				c_h = MAXXY;
				c_w = MAXXY * width / height;
			}
			BufferedImage bufferedImage = new BufferedImage(MAXXY, MAXXY, BufferedImage.TYPE_INT_RGB);

			Graphics2D g2d = bufferedImage.createGraphics();
			bufferedImage = g2d.getDeviceConfiguration().createCompatibleImage(MAXXY, MAXXY,
					Transparency.TRANSLUCENT);
			g2d.dispose();
			g2d = bufferedImage.createGraphics();
			g2d.drawImage(image, (MAXXY - c_w) / 2, (MAXXY - c_h) / 2, c_w, c_h, null);
			g2d.setColor(Color.GREEN);
			g2d.drawRect(0, 0, MAXXY - 1, MAXXY - 1);
			g2d.dispose();
			ImageIO.write(bufferedImage, "png", os);

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return os;
	}

}
